home *** CD-ROM | disk | FTP | other *** search
- /*
- * fsPipe.c --
- *
- * Routines for unnamed pipes. An unnamed pipe has a fixed length
- * resident buffer, a reading stream, and a writing stream.
- * Process migration can result in remotely accessed pipes.
- *
- * Copyright (C) 1985 Regents of the University of California
- * All rights reserved.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fsio/fsioPipe.c,v 9.12 92/08/10 17:26:55 mgbaker Exp $ SPRITE (Berkeley)";
- #endif not lint
-
-
- #include <sprite.h>
-
- #include <fs.h>
- #include <fsutil.h>
- #include <fsio.h>
- #include <fsNameOps.h>
- #include <fsconsist.h>
- #include <fsStat.h>
- #include <fsrmt.h>
- #include <vm.h>
- #include <proc.h>
- #include <rpc.h>
- #include <fsioPipe.h>
-
- #include <stdio.h>
- #include <recov.h>
-
- /*
- * Monitor to synchronize access to the openInstance in GetFileID.
- */
- static Sync_Lock pipeLock = Sync_LockInitStatic("Fs:pipeLock");
- #define LOCKPTR &pipeLock
-
- /*
- * Forward references.
- */
- static void GetFileID _ARGS_((Fs_FileID *fileIDPtr));
- extern Fsio_PipeIOHandle *Fsio_PipeHandleInit _ARGS_((Fs_FileID *fileIDPtr,
- Boolean findIt));
- static ReturnStatus PipeCloseInt _ARGS_((Fsio_PipeIOHandle *handlePtr,
- int ref, int write, Boolean release));
-
- /*
- * Migration debugging.
- */
- #ifdef MIG_DEBUG
-
- #define PIPE_CREATED(inStreamPtr, outStreamPtr) \
- { \
- printf("Create Pipe: Srvr %d Read <%d> Write <%d> I/O %d <%d,%d>\n", \
- (inStreamPtr)->hdr.fileID.serverID, \
- (inStreamPtr)->hdr.fileID.minor, \
- (outStreamPtr)->hdr.fileID.minor, \
- (inStreamPtr)->ioHandlePtr->fileID.serverID, \
- (inStreamPtr)->ioHandlePtr->fileID.major, \
- (inStreamPtr)->ioHandlePtr->fileID.minor); \
- }
-
- #define PIPE_CLOSE(streamPtr, handlePtr) \
- printf("Pipe Close: Stream %s <%d> I/O <%d,%d> ref %d write %d flags %x\n", \
- ((streamPtr)->flags & FS_READ) ? "Read" : "Write", \
- (streamPtr)->hdr.fileID.minor, \
- (handlePtr)->hdr.fileID.major, (handlePtr)->hdr.fileID.minor, \
- (handlePtr)->use.ref, (handlePtr)->use.write, \
- (handlePtr)->flags)
-
- #define PIPE_MIG_1(migInfoPtr, dstClientID) \
- printf("Pipe Migrate: %d => %d Stream %d <%d> I/O <%d,%d> migFlags %x ", \
- (migInfoPtr)->srcClientID, dstClientID, \
- (migInfoPtr)->streamID.serverID, (migInfoPtr)->streamID.minor, \
- (migInfoPtr)->ioFileID.major, (migInfoPtr)->ioFileID.minor, \
- (migInfoPtr)->flags);
-
- #define PIPE_MIG_2(migInfoPtr, closeSrcClient, handlePtr) \
- printf("=> %x\n closeSrc %d (ref %d write %d", (migInfoPtr)->flags, \
- closeSrcClient, (handlePtr)->use.ref, (handlePtr)->use.write);
-
- #define PIPE_MIG_3(handlePtr) \
- printf(" | ref %d write %d)\n", \
- (handlePtr)->use.ref, (handlePtr)->use.write);
-
- #define PIPE_MIG_END(handlePtr) \
- printf("PipeMigEnd: I/O <%d,%d> ref %d write %d\n", \
- (handlePtr)->hdr.fileID.major, (handlePtr)->hdr.fileID.minor, \
- (handlePtr)->use.ref, (handlePtr)->use.write)
- #else
-
- #define PIPE_CREATED(inStreamPtr, outStreamPtr)
- #define PIPE_CLOSE(streamPtr, handlePtr)
- #define PIPE_MIG_1(migInfoPtr, dstClientID)
- #define PIPE_MIG_2(migInfoPtr, closeSrcClient, handlePtr)
- #define PIPE_MIG_3(handlePtr)
- #define PIPE_MIG_END(handlePtr)
-
- #endif /* MIG_DEBUG */
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_CreatePipe --
- *
- * Create an unnamed pipe. Pointers to streams for both ends of the pipe
- * are returned in *inStreamPtrPtr and *outStreamPtrPtr.
- *
- * Results:
- * SUCCESS.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- Fsio_CreatePipe(inStreamPtrPtr, outStreamPtrPtr)
- Fs_Stream **inStreamPtrPtr; /* Return - in (reading) stream */
- Fs_Stream **outStreamPtrPtr; /* Return - out (writing) stream */
- {
- Fs_FileID fileID;
- register Fsio_PipeIOHandle *handlePtr;
- register Fs_Stream *streamPtr;
-
- /*
- * Set up the I/O handle for the pipe. The installation puts
- * one reference on the I/O handle.
- */
-
- GetFileID(&fileID);
- handlePtr = Fsio_PipeHandleInit(&fileID, FALSE);
- (void)Fsconsist_IOClientOpen(&handlePtr->clientList, rpc_SpriteID, FS_READ, FALSE);
- (void)Fsconsist_IOClientOpen(&handlePtr->clientList, rpc_SpriteID, FS_WRITE, FALSE);
-
- /*
- * Allocate and initialize the read, or "in", end of the stream.
- */
- streamPtr = Fsio_StreamCreate(rpc_SpriteID, rpc_SpriteID,
- (Fs_HandleHeader *)handlePtr,
- FS_READ | FS_USER, "read-pipe");
- Fsutil_HandleUnlock(streamPtr);
- *inStreamPtrPtr = streamPtr;
-
- /*
- * Set up the writing end. Note that we get a second reference to
- * the I/O handle by duping it.
- */
- Fsutil_HandleUnlock(handlePtr);
- (void)Fsutil_HandleDup((Fs_HandleHeader *)handlePtr);
- streamPtr = Fsio_StreamCreate(rpc_SpriteID, rpc_SpriteID,
- (Fs_HandleHeader *)handlePtr,
- FS_WRITE | FS_APPEND | FS_USER, "write-pipe");
- Fsutil_HandleUnlock(handlePtr);
- Fsutil_HandleUnlock(streamPtr);
- *outStreamPtrPtr = streamPtr;
-
- PIPE_CREATED(*inStreamPtrPtr, *outStreamPtrPtr);
-
- return(SUCCESS);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * GetFileID --
- *
- * Get a unique file ID for the pipe. This is a monitor to synchronize
- * access to the openInstance variable that gives us unique file
- * ids for unnamed pipes.
- *
- * Results:
- * Unique file ID.
- *
- * Side effects:
- * Open instance incremented.
- *
- *----------------------------------------------------------------------
- */
-
- static ENTRY void
- GetFileID(fileIDPtr)
- Fs_FileID *fileIDPtr;
- {
- static int openInstance = 0;
-
- LOCK_MONITOR;
-
- fileIDPtr->type = FSIO_LCL_PIPE_STREAM;
- fileIDPtr->serverID = rpc_SpriteID;
- fileIDPtr->major = 0;
- fileIDPtr->minor = openInstance;
- openInstance++;
-
- UNLOCK_MONITOR;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeHandleInit --
- *
- * Initialize a handle for a pipe.
- *
- * Results:
- * A pointer to the pipe handle.
- *
- * Side effects:
- * Create and install a handle for the file. It is returned locked
- * and with its reference count incremented if SUCCESS is returned.
- *
- *----------------------------------------------------------------------
- */
- Fsio_PipeIOHandle *
- Fsio_PipeHandleInit(fileIDPtr, findIt)
- Fs_FileID *fileIDPtr; /* Pipe file ID */
- Boolean findIt; /* TRUE if we expect to find its handle */
- {
- Fs_HandleHeader *hdrPtr;
- register Fsio_PipeIOHandle *handlePtr;
- register Boolean found;
-
- found = Fsutil_HandleInstall(fileIDPtr, sizeof(Fsio_PipeIOHandle), "pipe",
- FALSE, &hdrPtr);
- handlePtr = (Fsio_PipeIOHandle *)hdrPtr;
- if (!found) {
- if (findIt) {
- panic( "Fsio_PipeHandleInit, didn't find handle\n");
- }
- /*
- * When a pipe is created, it has one read and one write
- * reference on the handle.
- */
- handlePtr->use.ref = 2;
- handlePtr->use.write = 1;
- handlePtr->use.exec = 0;
- List_Init(&handlePtr->clientList);
- handlePtr->flags = 0;
- handlePtr->firstByte = handlePtr->lastByte = -1;
- handlePtr->buffer = (Address)malloc(FS_BLOCK_SIZE);
- handlePtr->bufSize = FS_BLOCK_SIZE;
- List_Init(&handlePtr->readWaitList);
- List_Init(&handlePtr->writeWaitList);
- fs_Stats.object.pipes++;
- }
- return(handlePtr);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeClose --
- *
- * Close a local pipe. Other processes waiting on the pipe are
- * unblocked and the pipe's buffer is freed when the last
- * user goes away.
- *
- * Results:
- * SUCCESS.
- *
- * Side effects:
- * Unblock local waiting reader (or writer) waiting on the pipe.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_PipeClose(streamPtr, clientID, procID, flags, dataSize, closeData)
- Fs_Stream *streamPtr; /* Stream to a pipe */
- int clientID; /* Host ID of closing process */
- Proc_PID procID; /* Process closing */
- int flags; /* Flags from the stream being closed */
- int dataSize; /* Should be 0 */
- ClientData closeData; /* Should be NIL */
- {
- register Fsio_PipeIOHandle *handlePtr =
- (Fsio_PipeIOHandle *)streamPtr->ioHandlePtr;
- Boolean cache = FALSE;
- ReturnStatus status;
-
- if (!Fsconsist_IOClientClose(&handlePtr->clientList, clientID, flags, &cache)) {
- printf( "Fsio_PipeClose, unknown client %d\n", clientID);
- Fsutil_HandleUnlock(handlePtr);
- } else {
- PIPE_CLOSE(streamPtr, handlePtr);
- status = PipeCloseInt(handlePtr, 1, (flags & FS_WRITE) != 0, TRUE);
- if (status != FS_FILE_REMOVED) {
- Fsutil_HandleRelease(handlePtr, TRUE);
- }
- }
- return(SUCCESS);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * PipeCloseInt --
- *
- * Do the real work of closing a pipe, given a variable number
- * of references.
- *
- * Results:
- * SUCCESS or FS_FILE_REMOVED, which indicates that the pipe has been
- * freed up.
- *
- * Side effects:
- * Unblock local waiting reader (or writer) waiting on the pipe.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- static ReturnStatus
- PipeCloseInt(handlePtr, ref, write, release)
- Fsio_PipeIOHandle *handlePtr; /* Pipe to clean up */
- int ref; /* Number of uses to remove */
- int write; /* Number of writers to remove */
- Boolean release; /* Whether to release handle to
- remove it. */
- {
- /*
- * Update the global/summary use counts for the file.
- */
- handlePtr->use.ref -= ref;
- handlePtr->use.write -= write;
- if (handlePtr->use.ref < 0 || handlePtr->use.write < 0) {
- panic("PipeCloseInt <%d,%d> use %d, write %d\n",
- handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor,
- handlePtr->use.ref, handlePtr->use.write);
- }
- if (write && handlePtr->use.write == 0) {
- /*
- * Notify reader that the writer has closed.
- */
- handlePtr->flags |= FSIO_PIPE_WRITER_GONE;
- Fsutil_FastWaitListNotify(&handlePtr->readWaitList);
- } else if (ref && handlePtr->use.ref == handlePtr->use.write) {
- /*
- * Update state and notify any blocked writers. Their write
- * will fail with no remaining readers.
- */
- handlePtr->flags |= FSIO_PIPE_READER_GONE;
- Fsutil_FastWaitListNotify(&handlePtr->writeWaitList);
- }
- if (handlePtr->flags == (FSIO_PIPE_WRITER_GONE|FSIO_PIPE_READER_GONE)) {
- free(handlePtr->buffer);
- Fsutil_WaitListDelete(&handlePtr->readWaitList);
- Fsutil_WaitListDelete(&handlePtr->writeWaitList);
- if (release) {
- Fsutil_HandleRelease(handlePtr, FALSE);
- }
- Fsutil_HandleRemove(handlePtr);
- fs_Stats.object.pipes--;
- return (FS_FILE_REMOVED);
- }
- /*
- * Handle will be released or unlocked by caller as appropriate.
- */
- return(SUCCESS);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeRead --
- *
- * Read on a pipe. Data is copied out of the pipe to satisfy the
- * read. If the pipe is empty this routine returns FS_WOULD_BLOCK.
- * If the pipe writer is gone this returns SUCCESS and 0 bytes
- * to simulate EOF.
- *
- * Results:
- * SUCCESS unless there was an address error or I/O error.
- *
- * Side effects:
- * Fill in the buffer. Notifies the pipe's writeWaitList after
- * removing data from the pipe.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_PipeRead(streamPtr, readPtr, waitPtr, replyPtr)
- Fs_Stream *streamPtr; /* Stream to read from */
- Fs_IOParam *readPtr; /* Read parameter block. */
- Sync_RemoteWaiter *waitPtr; /* Process info for remote waiting */
- Fs_IOReply *replyPtr; /* Signal to return, if any,
- * plus the amount read. */
- {
- ReturnStatus status = SUCCESS;
- register Fsio_PipeIOHandle *handlePtr =
- (Fsio_PipeIOHandle *)streamPtr->ioHandlePtr;
- int toRead;
- int startOffset;
- int startByte;
- int endByte;
-
- Fsutil_HandleLock(handlePtr);
-
- if (handlePtr->firstByte == -1) {
- /*
- * No data in the pipe. If there is no writer left then
- * return SUCCESS so the user process thinks of it as end of file,
- * otherwise block waiting for input.
- */
- replyPtr->length = 0;
- if (handlePtr->flags & FSIO_PIPE_WRITER_GONE) {
- status = SUCCESS;
- goto exit;
- } else {
- status = FS_WOULD_BLOCK;
- goto exit;
- }
- }
- /*
- * Compute the number of bytes that we can read from the pipe.
- */
- toRead = handlePtr->lastByte - handlePtr->firstByte + 1;
- if (toRead > readPtr->length) {
- toRead = readPtr->length;
- }
-
- /*
- * Compute offsets into the pipe buffer. The offsets float out past
- * the size of the buffer, but we use masks to take of the top bits.
- * We can also compare these top bits to determine if the valid range
- * of the buffer wraps around the end of the pipe.
- */
- startByte = handlePtr->firstByte;
- startOffset = startByte & FS_BLOCK_OFFSET_MASK;
- endByte = handlePtr->firstByte + toRead - 1;
-
- if ((startByte & ~FS_BLOCK_OFFSET_MASK) ==
- (endByte & ~FS_BLOCK_OFFSET_MASK)) {
- /*
- * Can do a straight copy, no wrap around necessary.
- */
- if (readPtr->flags & FS_USER) {
- if (Vm_CopyOut(toRead, handlePtr->buffer + startOffset, readPtr->buffer)
- != SUCCESS) {
- status = SYS_ARG_NOACCESS;
- }
- } else {
- bcopy(handlePtr->buffer + startOffset, readPtr->buffer, toRead);
- }
- } else {
- int numBytes;
- /*
- * Have to wrap around in the block so do it in two copies.
- */
- numBytes = FS_BLOCK_SIZE - startOffset;
- if (readPtr->flags & FS_USER) {
- if (Vm_CopyOut(numBytes, handlePtr->buffer + startOffset, readPtr->buffer)
- != SUCCESS) {
- status = SYS_ARG_NOACCESS;
- } else if (Vm_CopyOut(toRead - numBytes, handlePtr->buffer,
- readPtr->buffer + numBytes) != SUCCESS) {
- status = SYS_ARG_NOACCESS;
- }
- } else {
- bcopy(handlePtr->buffer + startOffset, readPtr->buffer, numBytes);
- bcopy(handlePtr->buffer, readPtr->buffer + numBytes, toRead - numBytes);
- }
- }
-
- /*
- * We just made space in the pipe so wake up blocked writers.
- */
- Fsutil_FastWaitListNotify(&handlePtr->writeWaitList);
-
- /*
- * Update the first byte and the parameters.
- */
- handlePtr->firstByte += toRead;
- if (handlePtr->firstByte > handlePtr->lastByte) {
- handlePtr->firstByte = -1;
- handlePtr->lastByte = -1;
- }
- replyPtr->length = toRead;
- exit:
- if (status == FS_WOULD_BLOCK) {
- Fsutil_FastWaitListInsert(&handlePtr->readWaitList, waitPtr);
- }
- Fsutil_HandleUnlock(handlePtr);
- return(status);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeWrite --
- *
- * Write on a pipe. This will put as much data as possible into the
- * pipe buffer, and then block the process (return would-block) if
- * there is any left over data. *lenPtr is updated to reflect how
- * much data was written to the pipe.
- *
- * Results:
- * SUCCESS unless there was an address error or I/O error.
- *
- * Side effects:
- * Fill the pipe from the buffer.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fsio_PipeWrite(streamPtr, writePtr, waitPtr, replyPtr)
- Fs_Stream *streamPtr; /* Stream to write to */
- Fs_IOParam *writePtr; /* Read parameter block */
- Sync_RemoteWaiter *waitPtr; /* Process info for remote waiting */
- Fs_IOReply *replyPtr; /* Signal to return, if any */
- {
- register ReturnStatus status = SUCCESS;
- register Fsio_PipeIOHandle *handlePtr =
- (Fsio_PipeIOHandle *)streamPtr->ioHandlePtr;
- int startOffset;
- register int toWrite;
- int startByte;
- int endByte;
-
- Fsutil_HandleLock(handlePtr);
-
- if (handlePtr->flags & FSIO_PIPE_READER_GONE) {
- replyPtr->length = 0;
- replyPtr->signal = SIG_PIPE;
- status = FS_BROKEN_PIPE;
- goto exit;
- }
-
- /*
- * Compute the number of bytes that will fit in the pipe. Remember
- * that the pipe can only hold one block of data.
- */
- if (handlePtr->firstByte == -1) {
- toWrite = FS_BLOCK_SIZE;
- } else {
- toWrite = FS_BLOCK_SIZE -
- (handlePtr->lastByte - handlePtr->firstByte + 1);
- }
- if (toWrite == 0) {
- /*
- * No room in the pipe.
- */
- replyPtr->length = 0;
- status = FS_WOULD_BLOCK;
- goto exit;
- } else if (toWrite > writePtr->length) {
- toWrite = writePtr->length;
- } else if (writePtr->length > toWrite) {
- /*
- * If there is more data to write we must block after writing the
- * data that we can.
- */
- status = FS_WOULD_BLOCK;
- }
- /*
- * Determine where to start and stop writing. Note that the firstByte
- * and lastByte offsets float out beyond the size of the pipe but
- * we use masks to clear off the extra high order bits.
- */
- startByte = handlePtr->lastByte + 1;
- startOffset = startByte & FS_BLOCK_OFFSET_MASK;
- endByte = handlePtr->lastByte + toWrite;
-
- if ((startByte & ~FS_BLOCK_OFFSET_MASK) ==
- (endByte & ~FS_BLOCK_OFFSET_MASK)) {
- /*
- * Can do a straight copy, no wrap around necessary.
- */
- if (writePtr->flags & FS_USER) {
- if (Vm_CopyIn(toWrite, writePtr->buffer, handlePtr->buffer + startOffset)
- != SUCCESS) {
- status = SYS_ARG_NOACCESS;
- }
- } else {
- bcopy(writePtr->buffer, handlePtr->buffer + startOffset, toWrite);
- }
- } else {
- int numBytes;
- /*
- * Have to wrap around in the block so do it in two copies.
- */
- numBytes = FS_BLOCK_SIZE - startOffset;
- if (writePtr->flags & FS_USER) {
- if (Vm_CopyIn(numBytes, writePtr->buffer, handlePtr->buffer + startOffset)
- != SUCCESS) {
- status = SYS_ARG_NOACCESS;
- } else if (Vm_CopyIn(toWrite - numBytes, writePtr->buffer + numBytes,
- handlePtr->buffer) != SUCCESS) {
- status = SYS_ARG_NOACCESS;
- }
- } else {
- bcopy(writePtr->buffer, handlePtr->buffer + startOffset, numBytes);
- bcopy(writePtr->buffer + numBytes, handlePtr->buffer, toWrite - numBytes);
- }
- }
-
- /*
- * We just wrote to the pipe so wake up blocked readers.
- */
- Fsutil_FastWaitListNotify(&handlePtr->readWaitList);
-
- /*
- * Update first byte, last byte and the parameters.
- */
- if (handlePtr->firstByte == -1) {
- handlePtr->firstByte = 0;
- }
- handlePtr->lastByte = endByte;
- replyPtr->length = toWrite;
- exit:
- if (status == FS_WOULD_BLOCK) {
- Fsutil_FastWaitListInsert(&handlePtr->writeWaitList, waitPtr);
- }
- Fsutil_HandleUnlock(handlePtr);
- return(status);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeIOControl --
- *
- * Check the IOC_CLEAR_FLAG control, and allow the IOC_SET_FLAG control.
- *
- * Results:
- * SUCCESS unless they try to clear the FS_APPEND flag.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_PipeIOControl(streamPtr, ioctlPtr, replyPtr)
- Fs_Stream *streamPtr;
- Fs_IOCParam *ioctlPtr; /* I/O Control parameter block */
- Fs_IOReply *replyPtr; /* Return length and signal */
- {
- register Fsio_PipeIOHandle *handlePtr =
- (Fsio_PipeIOHandle *)streamPtr->ioHandlePtr;
- register int command = ioctlPtr->command;
- ReturnStatus status = SUCCESS;
-
- switch(command) {
- case IOC_REPOSITION:
- return(FS_BAD_SEEK);
- case IOC_GET_FLAGS:
- case IOC_SET_BITS:
- return(SUCCESS);
- case IOC_CLEAR_BITS:
- case IOC_SET_FLAGS: {
- /*
- * Guard against turning off append mode in pipes.
- */
- int flags;
- int size;
- int inSize;
-
- if (ioctlPtr->inBufSize != sizeof(int)) {
- status = GEN_INVALID_ARG;
- } else if (ioctlPtr->format != mach_Format) {
- int fmtStatus;
- size = sizeof(int);
- inSize = ioctlPtr->inBufSize;
- fmtStatus = Fmt_Convert("w", ioctlPtr->format, &inSize,
- ioctlPtr->inBuffer, mach_Format, &size,
- (Address) &flags);
- if (fmtStatus != 0) {
- printf("Format of ioctl failed <0x%x>\n", fmtStatus);
- status = GEN_INVALID_ARG;
- }
- if (size != sizeof(int)) {
- status = GEN_INVALID_ARG;
- }
- } else {
- flags = *(int *)ioctlPtr->inBuffer;
- }
- if (status != SUCCESS) {
- return(status);
- }
- if ((command == IOC_SET_FLAGS && (flags & IOC_APPEND) == 0) ||
- (command == IOC_CLEAR_BITS && (flags & IOC_APPEND))) {
- return(GEN_INVALID_ARG);
- }
- return(SUCCESS);
- }
- case IOC_TRUNCATE:
- case IOC_LOCK:
- case IOC_UNLOCK:
- return(GEN_NOT_IMPLEMENTED);
- case IOC_NUM_READABLE: {
- int bytesAvailable = handlePtr->lastByte - handlePtr->firstByte;
-
- if (ioctlPtr->outBufSize != sizeof(int)) {
- status = GEN_INVALID_ARG;
- } else if (ioctlPtr->format != mach_Format) {
- int size = sizeof(int);
- int inSize = sizeof(int);
- int fmtStatus;
- fmtStatus = Fmt_Convert("w", mach_Format, &inSize,
- (Address) &bytesAvailable, ioctlPtr->format,
- &size, (Address) ioctlPtr->outBuffer);
- if (fmtStatus != 0) {
- printf("Format of ioctl failed <0x%x>\n", fmtStatus);
- status = GEN_INVALID_ARG;
- }
- if (size != sizeof(int)) {
- status = GEN_INVALID_ARG;
- }
- } else {
- *(int *)ioctlPtr->outBuffer = bytesAvailable;
- }
- return(status);
- }
- case IOC_GET_OWNER:
- case IOC_SET_OWNER:
- case IOC_MAP:
- case IOC_PREFIX:
- return(GEN_NOT_IMPLEMENTED);
- default:
- return(GEN_INVALID_ARG);
- }
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeSelect --
- *
- * Select on a pipe.
- *
- * Results:
- * SUCCESS unless there was an address error or I/O error.
- *
- * Side effects:
- * Fill the pipe from the buffer.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fsio_PipeSelect(hdrPtr, waitPtr, readPtr, writePtr, exceptPtr)
- Fs_HandleHeader *hdrPtr; /* The handle of the file */
- Sync_RemoteWaiter *waitPtr; /* Process info for waiting */
- int *readPtr; /* Read bit */
- int *writePtr; /* Write bit */
- int *exceptPtr; /* Exception bit */
- {
- register Fsio_PipeIOHandle *handlePtr = (Fsio_PipeIOHandle *)hdrPtr;
-
- Fsutil_HandleLock(hdrPtr);
- *exceptPtr = 0;
- if (*writePtr) {
- /*
- * Turn off writability if the pipe is full and there
- * are still readers. If there are no readers we allow
- * writing but the next write will fail.
- */
- if ((((handlePtr->firstByte + 1) % FS_BLOCK_SIZE) ==
- handlePtr->lastByte) &&
- ((handlePtr->flags & FSIO_PIPE_READER_GONE) == 0)) {
- if (waitPtr != (Sync_RemoteWaiter *)NIL) {
- Fsutil_FastWaitListInsert(&handlePtr->writeWaitList, waitPtr);
- }
- *writePtr = 0;
- }
- }
- if (*readPtr) {
- /*
- * If there's data to be read then set the READABLE bit.
- * If all the writers have died, then this process will never be
- * woken up again so lie and say the pipe is readble. The process
- * discover there's no writer when it tries to read the pipe.
- */
- if ((handlePtr->firstByte == -1) &&
- ((handlePtr->flags & FSIO_PIPE_WRITER_GONE) == 0)) {
- *readPtr = 0;
- if (waitPtr != (Sync_RemoteWaiter *)NIL) {
- Fsutil_FastWaitListInsert(&handlePtr->readWaitList, waitPtr);
- }
- }
- }
- Fsutil_HandleUnlock(hdrPtr);
- return(SUCCESS);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeGetIOAttr --
- *
- * Get the most up-to-date I/O attributes for a pipe.
- *
- * Results:
- * SUCCESS
- *
- * Side effects:
- * Updates the first and last byte indexes of the handle.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_PipeGetIOAttr(fileIDPtr, clientID, attrPtr)
- Fs_FileID *fileIDPtr; /* FileID of pipe */
- int clientID; /* IGNORED */
- register Fs_Attributes *attrPtr; /* Attributes to update */
- {
- Fsio_PipeIOHandle *handlePtr;
-
- handlePtr = Fsutil_HandleFetchType(Fsio_PipeIOHandle, fileIDPtr);
- if (handlePtr != (Fsio_PipeIOHandle *)NIL) {
- attrPtr->serverID = fileIDPtr->serverID;
- attrPtr->domain = fileIDPtr->major;
- attrPtr->fileNumber = fileIDPtr->minor;
- attrPtr->type = FS_LOCAL_PIPE;
- attrPtr->size = handlePtr->lastByte - handlePtr->firstByte +1;
- attrPtr->devServerID = fileIDPtr->serverID;
- Fsutil_HandleRelease(handlePtr, TRUE);
- }
- return(SUCCESS);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeSetIOAttr --
- *
- * Set the I/O attributes for a pipe. This doesn't do anything.
- *
- * Results:
- * SUCCESS
- *
- * Side effects:
- * Updates the first and last byte indexes of the handle.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_PipeSetIOAttr(fileIDPtr, attrPtr, flags)
- Fs_FileID *fileIDPtr; /* FileID of pipe */
- Fs_Attributes *attrPtr; /* Attributes to update */
- int flags; /* What attrs to set */
- {
- return(SUCCESS);
- }
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Fsio_PipeMigClose --
- *
- * Release a reference on a Pipe I/O handle.
- *
- * Results:
- * SUCCESS.
- *
- * Side effects:
- * Release the I/O handle.
- *
- * ----------------------------------------------------------------------------
- *
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_PipeMigClose(hdrPtr, flags)
- Fs_HandleHeader *hdrPtr; /* File being released */
- int flags; /* Use flags from the stream */
- {
- panic("Fsio_PipeMigClose called\n");
- Fsutil_HandleRelease(hdrPtr, FALSE);
- return(SUCCESS);
- }
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Fsio_PipeMigrate --
- *
- * This takes care of transfering references from one client to the other.
- * A useful side-effect of this routine is to properly set the type in
- * the ioFileID, either FSIO_LCL_PIPE_STREAM or FSIO_RMT_PIPE_STREAM.
- * In the latter case FsrmtPipeMigrate is called to do all the work.
- *
- * Results:
- * An error status if the I/O handle can't be set-up.
- * Otherwise SUCCESS is returned, *flagsPtr may have the FS_RMT_SHARED
- * bit set, and *sizePtr and *dataPtr are set to reference Fsio_DeviceState.
- *
- * Side effects:
- * Sets the correct stream type on the ioFileID.
- * Shifts client references from the srcClient to the destClient.
- *
- * ----------------------------------------------------------------------------
- *
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_PipeMigrate(migInfoPtr, dstClientID, flagsPtr, offsetPtr, sizePtr, dataPtr)
- Fsio_MigInfo *migInfoPtr; /* Migration state */
- int dstClientID; /* ID of target client */
- int *flagsPtr; /* In/Out Stream usage flags */
- int *offsetPtr; /* Return - new stream offset (not needed) */
- int *sizePtr; /* Return - sizeof(Fsio_DeviceState) */
- Address *dataPtr; /* Return - pointer to Fsio_DeviceState */
- {
- Fsio_PipeIOHandle *handlePtr;
- Boolean closeSrcClient;
-
- if (migInfoPtr->ioFileID.serverID != rpc_SpriteID) {
- /*
- * The pipe was local, which is usually true, but is now remote.
- */
- migInfoPtr->ioFileID.type = FSIO_RMT_PIPE_STREAM;
- return(FsrmtPipeMigrate(migInfoPtr, dstClientID, flagsPtr, offsetPtr,
- sizePtr, dataPtr));
- }
- migInfoPtr->ioFileID.type = FSIO_LCL_PIPE_STREAM;
- handlePtr = Fsio_PipeHandleInit(&migInfoPtr->ioFileID, TRUE);
-
- PIPE_MIG_1(migInfoPtr, dstClientID);
- /*
- * At the stream level, add the new client to the set of clients
- * for the stream, and check for any cross-network stream sharing.
- */
- Fsio_StreamMigClient(migInfoPtr, dstClientID, (Fs_HandleHeader *)handlePtr,
- &closeSrcClient);
- /* XXX The above is a reference to the remote guy we've got a handle for,
- * since we're the server and have the ioHandle with the buffer. I guess this
- * means that closeSrcClient must be false? Or maybe both things happen and
- * this is used for unmigrating too?
- */
- PIPE_MIG_2(migInfoPtr, closeSrcClient, handlePtr);
-
- /*
- * Adjust use counts on the I/O handle to reflect any new sharing.
- */
- Fsio_MigrateUseCounts(migInfoPtr->flags, closeSrcClient, &handlePtr->use);
- PIPE_MIG_3(handlePtr);
-
- /*
- * Move the client at the I/O handle level.
- */
- /* XXX Do I need to do something here? */
- Fsio_MigrateClient(&handlePtr->clientList, migInfoPtr->srcClientID,
- dstClientID, migInfoPtr->flags, closeSrcClient);
-
- /* XXX So now put newish handle in recov table? */
- *sizePtr = 0;
- *dataPtr = (Address)NIL;
- *flagsPtr = migInfoPtr->flags;
- *offsetPtr = migInfoPtr->offset;
- /*
- * We don't need this reference on the I/O handle; there is no change.
- */
- Fsutil_HandleRelease(handlePtr, TRUE);
- return(SUCCESS);
- }
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Fsio_PipeMigOpen --
- *
- * Complete setup of a FSIO_LCL_PIPE_STREAM after migration (back) to the
- * pipe I/O server. Fsio_PipeMigrate has done the work of shifting use
- * counts at the stream and I/O handle level. This routine has to
- * increment the low level reference count on the pipe I/O handle
- * to reflect the existence of a new stream to the I/O handle.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------------
- *
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_PipeMigOpen(migInfoPtr, size, data, hdrPtrPtr)
- Fsio_MigInfo *migInfoPtr; /* Migration state */
- int size; /* Zero */
- ClientData data; /* NIL */
- Fs_HandleHeader **hdrPtrPtr; /* Return - handle for the file */
- {
- register Fsio_PipeIOHandle *handlePtr;
-
- handlePtr = Fsutil_HandleFetchType(Fsio_PipeIOHandle, &migInfoPtr->ioFileID);
- if (handlePtr == (Fsio_PipeIOHandle *)NIL) {
- panic( "Fsio_PipeMigOpen, no handle\n");
- return(FAILURE);
- } else {
- PIPE_MIG_END(handlePtr);
- Fsutil_HandleUnlock(handlePtr);
- *hdrPtrPtr = (Fs_HandleHeader *)handlePtr;
- return(SUCCESS);
- }
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeReopen --
- *
- * Reopen a pipe for a client. This executed on a server and will
- * only work if it was a network partition that made us forget
- * about the client. If we've already removed the pipe handle
- * then the clien't won't be able to recover.
- *
- * Results:
- * A non-SUCCESS return code if the re-open failed.
- *
- * Side effects:
- * Adds the client to the set of client's for the pipe.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- ReturnStatus
- Fsio_PipeReopen(hdrPtr, clientID, inData, outSizePtr, outDataPtr)
- Fs_HandleHeader *hdrPtr; /* NIL */
- int clientID; /* Host ID of client */
- ClientData inData; /* sizeof Fsio_PipeReopenParams */
- int *outSizePtr; /* Returns 0 */
- ClientData *outDataPtr; /* Returns NIL */
- {
- register Fsio_PipeIOHandle *handlePtr;
- ReturnStatus status;
- Fsio_PipeReopenParams *reopenParamsPtr;
-
- reopenParamsPtr = (Fsio_PipeReopenParams *)inData;
- *outSizePtr = 0;
- *outDataPtr = (ClientData)NIL;
-
- /*
- * Old clients may still do reopens of pipes with no references (at least,
- * they do this with devices with no references), so protect ourselves
- * here on the server. But since we don't recover pipes except after
- * network partitions, this may not be necessary.
- */
- if (reopenParamsPtr->use.ref == 0) {
- return SUCCESS;
- }
-
- handlePtr = Fsutil_HandleFetchType(Fsio_PipeIOHandle, &reopenParamsPtr->fileID);
- if (handlePtr == (Fsio_PipeIOHandle *)NIL) {
- status = FAILURE;
- } else {
- Fsconsist_IOClientStatus(&handlePtr->clientList, clientID,
- &reopenParamsPtr->use);
- (void)Fsconsist_IOClientReopen(&handlePtr->clientList, clientID,
- &reopenParamsPtr->use);
- handlePtr->use.ref += reopenParamsPtr->use.ref;
- handlePtr->use.write += reopenParamsPtr->use.write;
- Fsutil_HandleRelease(handlePtr, TRUE);
- status = SUCCESS;
- }
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeClientKill --
- *
- * Clean up after a crashed client. Note, this doesn't handle the
- * obscure case of one end of a pipe being duplicated and then
- * one of the sharers migrating to a host which crashes. In this
- * funny case we'll wrongly think that all users of one end of
- * the pipe have crashed.
- *
- * Results:
- * SUCCESS.
- *
- * Side effects:
- * Removes the client (if applicable) from the pipe's set of clients.
- * This will cause a FS_BROKEN_PIPE error unless the pipe is re-opened,
- * which might happen in a network partition. This unlocks the handle.
- *
- *----------------------------------------------------------------------
- */
- void
- Fsio_PipeClientKill(hdrPtr, clientID)
- Fs_HandleHeader *hdrPtr; /* Handle to clean up */
- int clientID; /* Host assumed down */
- {
- register Fsio_PipeIOHandle *handlePtr = (Fsio_PipeIOHandle *)hdrPtr;
- int refs, writes, execs;
- register ReturnStatus status;
-
- Fsconsist_IOClientKill(&handlePtr->clientList, clientID, &refs, &writes, &execs);
- status = PipeCloseInt(handlePtr, refs, writes, FALSE);
- if (status != FS_FILE_REMOVED) {
- Fsutil_HandleUnlock(handlePtr);
- }
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeScavenge --
- *
- * Scavenge a pipe. The handle might be usless if all its
- * client's have crashed.
- *
- * Results:
- * TRUE if the handle was removed.
- *
- * Side effects:
- * Unlocks the pipe's handle.
- *
- *----------------------------------------------------------------------
- */
- Boolean
- Fsio_PipeScavenge(hdrPtr)
- Fs_HandleHeader *hdrPtr; /* Handle about to be deleted */
- {
- #ifdef notdef
- register Fsio_PipeIOHandle *handlePtr = (Fsio_PipeIOHandle *)hdrPtr;
- if (List_IsEmpty(&handlePtr->clientList) &&
- (handlePtr->flags == (FSIO_PIPE_WRITER_GONE|FSIO_PIPE_READER_GONE))) {
- /*
- * Never scavenge pipe handles. Regular recovery cleanup
- * should invoke the pipe close routines and do proper cleanup.
- */
- free(handlePtr->buffer);
- Fsutil_WaitListDelete(&handlePtr->readWaitList);
- Fsutil_WaitListDelete(&handlePtr->writeWaitList);
- Fsutil_HandleRemove(hdrPtr);
- fs_Stats.object.pipes--;
- return(TRUE);
- }
- #endif notdef
- Fsutil_HandleUnlock(hdrPtr);
- return(FALSE);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeRecovTestUseCount --
- *
- * For recovery testing, return the use count on the io handle.
- *
- * Results:
- * The use count.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int
- Fsio_PipeRecovTestUseCount(handlePtr)
- Fsio_PipeIOHandle *handlePtr;
- {
- return handlePtr->use.ref;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fsio_PipeSetupHandle --
- *
- * Given a pipe recovery object, setup the necessary handle state for it.
- *
- * Results:
- * None.
- *
- * Side effects:
- * A handle is created in put in the handle table.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fsio_PipeSetupHandle(recovInfoPtr)
- Fsrecov_HandleState *recovInfoPtr;
- {
- Fs_FileID fileID;
- int clientID;
- Fsio_PipeIOHandle *handlePtr;
-
- if (!recov_Transparent) {
- panic("Fsio_PipeSetupHandle: shouldn't have been called.");
- }
- fileID = recovInfoPtr->fileID;
- clientID = fileID.serverID;
- fileID.serverID = rpc_SpriteID;
-
- handlePtr = Fsutil_HandleFetchType(Fsio_PipeIOHandle, &fileID);
- if (handlePtr == (Fsio_PipeIOHandle *) NIL) {
- return FAILURE;
- }
- (void)Fsconsist_IOClientReopen(&handlePtr->clientList, clientID,
- &recovInfoPtr->use);
- handlePtr->use.ref += recovInfoPtr->use.ref;
- handlePtr->use.write += recovInfoPtr->use.write;
- Fsutil_HandleRelease(handlePtr, TRUE);
-
- return SUCCESS;
- }
-